#include "A_Config.h"
#include "JPEGDEC.h"
JPEGDEC jpeg;
#define PHOTO_DIR "/PHOTO"

class AppImgViewer : public AppBase
{
private:
    /* data */
    void createList();
    void listDir(const char *dirname);

public:
    AppImgViewer()
    {
        name = "imgviewer";
        title = "图片查看器";
        description = "查看TF卡 PHOTOS文件夹下的图片";
        image = "\xEF\x80\xBE";
    }
    void setup();
    void loop();
    void destruct();
};

static lv_color_t *canvas_buffer = NULL;
static lv_obj_t *canvas_img = NULL;
static lv_obj_t *list_img = NULL;
static bool del_req = false;
static char filenameToPrint[80] = "/";
static void listDir(const char *dirname);

static int drawToCanvas(JPEGDRAW *pDraw)
{
    int w = pDraw->iWidth;
    int h = pDraw->iHeight;
    for (int16_t i = 0; i < w; i++)
    {
        for (int16_t j = 0; j < h; j++)
        {
            lv_color16_t c;
            c.full = pDraw->pPixels[i + j * w];
            lv_canvas_set_px(canvas_img, pDraw->x + i, pDraw->y + j, c);
        }
    }
    return 1;
} /* drawMCUs() */
static int image_w, image_h;
static int image_w_raw, image_h_raw;
static int16_t *imgPixels;
static int drawToPrinter(JPEGDRAW *pDraw)
{
    int w = pDraw->iWidth;
    int h = pDraw->iHeight;
    for (int y = 0; y < h; y++)
    {
        for (int x = 0; x < w; x++)
        {
            int x_1 = x + pDraw->x;
            int y_1 = y + pDraw->y;
            int idx = x + y * w;
            x_1 = x_1 * image_w;
            x_1 = x_1 / image_w_raw;
            y_1 = y_1 * image_h;
            y_1 = y_1 / image_h_raw;
            uint16_t pixelR = (pDraw->pPixels[idx] & 0xF800) >> 8;
            uint16_t pixelG = (pDraw->pPixels[idx] & 0x07E0) >> 3;
            uint16_t pixelB = (pDraw->pPixels[idx] & 0x001F) << 3;
            imgPixels[x_1 + y_1 * image_w] = (pixelR * (77) + pixelG * (150) + pixelB * (29)) >> 8;
            if (imgPixels[x_1 + y_1 * image_w] > 255)
                imgPixels[x_1 + y_1 * image_w] = 255;
        }
    }

    return 1;
}

static void load_image(const char *filename)
{
    lv_canvas_fill_bg(canvas_img, lv_color_black(), LV_OPA_COVER);
    // xSemaphoreTake(hal.SPILock, portMAX_DELAY);
    File f = SDCARD.open(filename, "r");
    if (f)
    {
        if (jpeg.open(f, drawToCanvas))
        {
            strcpy(filenameToPrint, filename);
            jpeg.setPixelType(RGB565_LITTLE_ENDIAN);
            uint32_t h = jpeg.getHeight() / 4;
            if (h > 240)
                h = 240;
            uint32_t w = jpeg.getWidth() / 4;
            if (w > 320)
                w = 320;
            jpeg.decode((320 - w) / 2, (240 - h) / 2, JPEG_SCALE_QUARTER);
            jpeg.close();
            lv_obj_invalidate(canvas_img);
        }
        f.close();
    }
    // xSemaphoreGive(hal.SPILock);
}

static void print_image(const char *filename)
{
    // xSemaphoreTake(hal.wiremutex, portMAX_DELAY);
    if (printer.testConnection())
    {
        // xSemaphoreTake(hal.SPILock, portMAX_DELAY);
        File f = SDCARD.open(filename, "r");
        if (f)
        {
            printer.clearBuffer(PRINTER_BUFFER_SIZE);
            printer.rotate = true;
            if (jpeg.open(f, drawToPrinter))
            {
                jpeg.setPixelType(RGB565_LITTLE_ENDIAN);
                image_w_raw = jpeg.getWidth();
                image_h_raw = jpeg.getHeight();
                image_h = 384;
                image_w = image_w_raw * 384;
                image_w = image_w / image_h_raw;
                imgPixels = (int16_t *)ps_malloc(image_w * image_h * 2);
                jpeg.decode(0, 0, 0);
                jpeg.close();
                for (int j = 0; j < image_h; j++)
                {
                    for (int i = 0; i < image_w; i++)
                    {
                        int16_t oldPixel = constrain(imgPixels[i + j * image_w], 0, 0xFF);
                        int16_t newPixel = oldPixel & 0x80; // or 0x30 to dither to 2-bit directly. much improved tonal range, but more horizontal banding between blocks.
                        imgPixels[i + j * image_w] = newPixel;
                        int quantError = oldPixel - newPixel;
                        if (i + 1 < image_w)
                            imgPixels[i + 1 + j * image_w] += quantError * 7 / 16;
                        if ((i - 1 >= 0) && (j + 1 < image_h))
                            imgPixels[i - 1 + (j + 1) * image_w] += quantError * 3 / 16;
                        if (j + 1 < image_h)
                            imgPixels[i + (j + 1) * image_w] += quantError * 5 / 16;
                        if ((i + 1 < image_w) && (j + 1 < image_h))
                            imgPixels[i + 1 + (j + 1) * image_w] += quantError * 1 / 16;
                    }
                }
                for (int j = 0; j < image_h; j++)
                {
                    for (int i = 0; i < image_w; i++)
                    {
                        if (imgPixels[i + j * image_w] < 128)
                            printer.drawDot(i, j, true);
                        else
                            printer.drawDot(i, j, false);
                    }
                }
                printer.sendBuffer();
                printer.gomm(5);
                free(imgPixels);
                imgPixels = NULL;
            }
            f.close();
        }
        // xSemaphoreGive(hal.SPILock);
    }
    // xSemaphoreGive(hal.wiremutex);
}

static void event_btn_print_click(lv_event_t *e)
{
    print_image(filenameToPrint);
}

static void event_btn_del_click(lv_event_t *e)
{
    del_req = true;
}

static void event_img_select(lv_event_t *e)
{
    lv_event_code_t code = lv_event_get_code(e);
    lv_obj_t *obj = lv_event_get_target(e);
    if (code == LV_EVENT_CLICKED)
    {
        char tmp[40] = {0};
        strcat(tmp, "/PHOTO/PICT");
        strcat(tmp, lv_list_get_btn_text(list_img, obj));
        load_image(tmp);
    }
}

void AppImgViewer::createList()
{
    list_img = lv_list_create(scr);
    lv_obj_set_size(list_img, 160, lv_pct(60));
    lv_obj_align(list_img, LV_ALIGN_BOTTOM_LEFT, 0, 0);
    lv_obj_add_flag(list_img, LV_OBJ_FLAG_SCROLL_MOMENTUM);
}

void AppImgViewer::listDir(const char *dirname)
{
    // xSemaphoreTake(hal.SPILock, portMAX_DELAY);
    LOCKLV();
    if (list_img)
        lv_obj_del(list_img);
    createList();
    File root = SDCARD.open(dirname);
    if (!root)
    {
        lv_toast("无法打开文件");
        UNLOCKLV();
        // xSemaphoreGive(hal.SPILock);
        return;
    }
    File file = root.openNextFile();
    while (file)
    {
        if (!file.isDirectory())
        {
            lv_obj_t *btn = lv_list_add_btn(list_img, NULL, file.path() + 7 + 4);
            lv_obj_set_style_text_font(btn, &lv_font_chinese_16, 0);
            lv_obj_add_event_cb(btn, event_img_select, LV_EVENT_CLICKED, NULL);
        }
        file = root.openNextFile();
    }
    UNLOCKLV();
    // xSemaphoreGive(hal.SPILock);
}

void AppImgViewer::setup()
{
    LOCKLV();
    canvas_img = lv_canvas_create(scr);

    canvas_buffer = (lv_color_t *)ps_malloc(sizeof(lv_color_t) * 320 * 240);
    lv_canvas_set_buffer(canvas_img, canvas_buffer, 320, 240, LV_IMG_CF_TRUE_COLOR);
    lv_canvas_fill_bg(canvas_img, lv_color_black(), LV_OPA_COVER);
    lv_obj_align(canvas_img, LV_ALIGN_CENTER, 0, 0);

    lv_obj_t *btnPrint = lv_btn_create(scr);
    lv_obj_set_style_radius(btnPrint, LV_RADIUS_CIRCLE, 0);
    lv_obj_set_size(btnPrint, 40, 40);
    lv_obj_align_to(btnPrint, canvas_img, LV_ALIGN_BOTTOM_RIGHT, 0, 0);
    lv_obj_add_event_cb(btnPrint, event_btn_print_click, LV_EVENT_CLICKED, NULL);

    lv_obj_t *btnDel = lv_btn_create(scr);
    lv_obj_set_style_bg_color(btnDel, lv_palette_main(LV_PALETTE_RED), 0);
    lv_obj_set_style_radius(btnDel, LV_RADIUS_CIRCLE, 0);
    lv_obj_set_size(btnDel, 40, 40);
    lv_obj_align_to(btnDel, btnPrint, LV_ALIGN_OUT_LEFT_MID, 0, 0);
    lv_obj_add_event_cb(btnDel, event_btn_del_click, LV_EVENT_CLICKED, NULL);

    createList();

    UNLOCKLV();
    listDir(PHOTO_DIR);
}

void AppImgViewer::loop()
{
    if (del_req)
    {
        del_req = false;
        if (msgbox_yn("是否删除照片？"))
        {
            // xSemaphoreTake(hal.SPILock, portMAX_DELAY);
            if (SDCARD.remove(filenameToPrint))
            {
                // xSemaphoreGive(hal.SPILock);
                listDir(PHOTO_DIR);
                // xSemaphoreTake(hal.SPILock, portMAX_DELAY);
            }
            // xSemaphoreGive(hal.SPILock);
        }
    }
    if (hal.axpShortPress)
    {
        hal.axpShortPress = false;
        appManager.goBack();
        return;
    }
}

void AppImgViewer::destruct()
{
    free(canvas_buffer);
}

static AppImgViewer app;